﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ImageUtility.cs" company="">
//   
// </copyright>
// <summary>
//   The image utility.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Libium.Drawing
{
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Runtime.InteropServices;

    using Libium.Core;

    /// <summary>
    /// The image utility.
    /// </summary>
    public static class ImageUtility
    {
        #region Public Methods and Operators

        /// <summary>
        /// The dib bytes to image.
        /// </summary>
        /// <param name="bytes">
        /// The bytes.
        /// </param>
        /// <returns>
        /// The <see cref="Image"/>.
        /// </returns>
        public static Image DibBytesToImage(byte[] bytes)
        {
            var infoHeader = ConvertUtility.BytesToStruct<BITMAPINFOHEADER>(bytes);

            var fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
            var infoHeaderSize = infoHeader.biSize;
            var fileSize = fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage;

            var fileHeader = new BITMAPFILEHEADER
                {
                    bfType = BITMAPFILEHEADER.BM, 
                    bfSize = fileSize, 
                    bfReserved1 = 0, 
                    bfReserved2 = 0, 
                    bfOffBits = fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4
                };

            var fileHeaderBytes = ConvertUtility.StructToBytes(fileHeader);

            var stream = new MemoryStream();
            stream.Write(fileHeaderBytes, 0, fileHeaderSize);
            stream.Write(bytes, 0, bytes.Length);
            stream.Seek(0, SeekOrigin.Begin);

            return Image.FromStream(stream);
        }

        /// <summary>
        /// The dib stream to image.
        /// </summary>
        /// <param name="stream">
        /// The stream.
        /// </param>
        /// <returns>
        /// The <see cref="Image"/>.
        /// </returns>
        public static Image DibStreamToImage(Stream stream)
        {
            var bytes = stream.CopyToArray();
            return DibBytesToImage(bytes);
        }

        /// <summary>
        /// The get mime type.
        /// </summary>
        /// <param name="format">
        /// The format.
        /// </param>
        /// <returns>
        /// The <see cref="MimeType"/>.
        /// </returns>
        /// <exception cref="NotSupportedException">
        /// </exception>
        public static MimeType GetMimeType(ImageFormat format)
        {
            if (Equals(format, ImageFormat.Bmp))
            {
                return MimeTypes.Bmp;
            }

            if (Equals(format, ImageFormat.Emf))
            {
                return MimeTypes.Emf;
            }

            if (Equals(format, ImageFormat.Exif))
            {
                return MimeTypes.Exif;
            }

            if (Equals(format, ImageFormat.Gif))
            {
                return MimeTypes.Gif;
            }

            if (Equals(format, ImageFormat.Icon))
            {
                return MimeTypes.Icon;
            }

            if (Equals(format, ImageFormat.Jpeg))
            {
                return MimeTypes.Jpg;
            }

            if (Equals(format, ImageFormat.MemoryBmp))
            {
                return MimeTypes.Bmp;
            }

            if (Equals(format, ImageFormat.Png))
            {
                return MimeTypes.Png;
            }

            if (Equals(format, ImageFormat.Tiff))
            {
                return MimeTypes.Tiff;
            }

            if (Equals(format, ImageFormat.Wmf))
            {
                return MimeTypes.Wmf;
            }

            throw new NotSupportedException("Not supported image format" + format);
        }

        #endregion

        /// <summary>
        /// The bitmapfileheader.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 2)]
        private struct BITMAPFILEHEADER
        {
            /// <summary>
            /// The bm.
            /// </summary>
            public static readonly short BM = 0x4d42; // BM

            /// <summary>
            /// The bf type.
            /// </summary>
            public short bfType;

            /// <summary>
            /// The bf size.
            /// </summary>
            public int bfSize;

            /// <summary>
            /// The bf reserved 1.
            /// </summary>
            public short bfReserved1;

            /// <summary>
            /// The bf reserved 2.
            /// </summary>
            public short bfReserved2;

            /// <summary>
            /// The bf off bits.
            /// </summary>
            public int bfOffBits;
        }

        /// <summary>
        /// The bitmapinfoheader.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct BITMAPINFOHEADER
        {
            /// <summary>
            /// The bi size.
            /// </summary>
            public readonly int biSize;

            /// <summary>
            /// The bi width.
            /// </summary>
            public readonly int biWidth;

            /// <summary>
            /// The bi height.
            /// </summary>
            public readonly int biHeight;

            /// <summary>
            /// The bi planes.
            /// </summary>
            public readonly short biPlanes;

            /// <summary>
            /// The bi bit count.
            /// </summary>
            public readonly short biBitCount;

            /// <summary>
            /// The bi compression.
            /// </summary>
            public readonly int biCompression;

            /// <summary>
            /// The bi size image.
            /// </summary>
            public readonly int biSizeImage;

            /// <summary>
            /// The bi x pels per meter.
            /// </summary>
            public readonly int biXPelsPerMeter;

            /// <summary>
            /// The bi y pels per meter.
            /// </summary>
            public readonly int biYPelsPerMeter;

            /// <summary>
            /// The bi clr used.
            /// </summary>
            public readonly int biClrUsed;

            /// <summary>
            /// The bi clr important.
            /// </summary>
            public readonly int biClrImportant;
        }
    }
}